package com.mangosteen.app.controller;

import com.mangosteen.app.annotation.CurrentUserId;
import com.mangosteen.app.exception.InvalidParameterException;
import com.mangosteen.app.exception.ResourceNotFoundException;
import com.mangosteen.app.manager.TagManager;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

@RestController
@RequestMapping("v1.0/tags")
@Tag(name = "Tag APIs", description = "Related APIs for Tag management")
public class TagController {
    private final TagManager tagManager;

    @Autowired
    public TagController(TagManager tagManager) {
        this.tagManager = tagManager;
    }

    //创建tag
    @PostMapping(produces = "application/json",consumes = "application/json")
    @Operation(summary = "Create Tag", description = "Return the specific tag information",
        responses = {
            @ApiResponse(responseCode = "200", description = "Tag created successfully"),
            @ApiResponse(responseCode = "400", description = "Tag input invalid"),
            @ApiResponse(responseCode = "500", description = "Tag created failed")
        })
    ResponseEntity<com.mangosteen.app.model.dao.Tag> createTag(@CurrentUserId Long id,
                                                               @RequestBody com.mangosteen.app.model.dao.Tag tag) {
        //todo: tag name 不允许重复
        checkTag(id, tag);
        return ResponseEntity.ok(tagManager.createTag(tag,id));
    }
    //修改tag
    @PatchMapping(produces = "application/json",consumes = "application/json")
    @Operation(summary = "Update Tag", description = "Return the updated tag information",
        responses = {
            @ApiResponse(responseCode = "200", description = "Tag created successfully"),
            @ApiResponse(responseCode = "400", description = "Tag created failed"),
            @ApiResponse(responseCode = "500", description = "Tag created failed")
        })
    ResponseEntity<com.mangosteen.app.model.dao.Tag> updateTag(@CurrentUserId Long userId,
                                                               @RequestBody com.mangosteen.app.model.dao.Tag tagToUpdate) {
        //todo: tag name 不允许重复
        checkTagNeedToUpdate(userId, tagToUpdate);
        return ResponseEntity.ok(tagManager.updateTag(tagToUpdate));
    }

    @GetMapping(path="/{id}",produces = "application/json",consumes = "application/json")
    @Operation(summary = "Get Tag", description = "Return the specific tag information",
    responses = {
            @ApiResponse(responseCode = "200", description = "Tag fetch successfully"),
            @ApiResponse(responseCode = "400", description = "Tag input failed"),
            @ApiResponse(responseCode = "404", description = "Tag id not found"),
            @ApiResponse(responseCode = "500", description = "Tag fetch failed")
    })
    ResponseEntity<com.mangosteen.app.model.dao.Tag> getTagByTagId(@CurrentUserId Long userId,
                                                                   @PathVariable("id") Long tagId){
        if(tagId==null|| tagId<0L){
            throw new InvalidParameterException("The tag id must be not empty and positive. tag id: "+tagId);
        }
        val tag = Optional.ofNullable(tagManager.getTagByTagId(tagId))
                            .orElseThrow(()->new ResourceNotFoundException("There is no related tag,tag id:"
                                    + tagId));
        return ResponseEntity.ok(tag);
    }

    @DeleteMapping(path="/{id}",produces = "application/json",consumes = "application/json")
    @Operation(summary = "Delete Tag", description = "Return the deleted tag information",
            responses = {
                    @ApiResponse(responseCode = "200", description = "Tag deleted successfully"),
                    @ApiResponse(responseCode = "400", description = "Tag input failed"),
                    @ApiResponse(responseCode = "404", description = "Tag id not found"),
                    @ApiResponse(responseCode = "500", description = "Tag deleted failed")
            })
    ResponseEntity<com.mangosteen.app.model.dao.Tag> deleteTag(@CurrentUserId Long userId,
                                                               @PathVariable("id") Long tagId){
        if(tagId==null|| tagId<0L){
            throw new InvalidParameterException("The tag id must be not empty and positive. tag id: "+tagId);
        }
        val tag = Optional.ofNullable(tagManager.getTagByTagId(tagId))
                .orElseThrow(()->new ResourceNotFoundException("There is no related tag,tag id:"
                        + tagId));
        if(!tag.getUserId().equals(userId)){
            throw new InvalidParameterException(
                    String.format("The tag id %d and user id %d is not matched",
                            tag.getId(),userId));
        }
        tagManager.deleteTagByTagId(tagId);
        return ResponseEntity.ok(tag);
    }
    private void checkTag(Long id, com.mangosteen.app.model.dao.Tag tag) {
        if(tag.getName().isEmpty()){
            throw new InvalidParameterException("The tag name must be not empty");
        }else if ( tagManager.checkTagExisted(tag.getName(), id)){
            throw new InvalidParameterException("The tag name already existed");
        }
    }

    private void checkTagNeedToUpdate(Long userId, com.mangosteen.app.model.dao.Tag tagToUpdate){
        if(tagToUpdate.getId()==null){
            throw new InvalidParameterException("The tag id should not be empty");
        }
        if(tagToUpdate.getName() == null
                && tagToUpdate.getDescription()== null
                && tagToUpdate.getIcon()== null){
            throw new InvalidParameterException("There is no any information to update for tag");
        }
        val tag = Optional.ofNullable(tagManager.getTagByTagId(tagToUpdate.getId()))
                .orElseThrow(()->new ResourceNotFoundException("There is no related tag to update,tag id:"
                                                                +tagToUpdate.getId()));

        if(!tag.getUserId().equals(userId)){
            throw new InvalidParameterException(
                    String.format("The tag id %d and user id %d is not matched",
                            tag.getId(),userId));
        }
    }
}
